# -*- coding: utf-8 -*-
#   /**
#   * Copyright (c) 2022 Beijing Jiaotong University
#   * PhotLab is licensed under [Open Source License].
#   * You can use this software according to the terms and conditions of the [Open Source License].
#   * You may obtain a copy of [Open Source License] at: [https://open.source.license/]
#   *
#   * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
#   * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
#   * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#   *
#   * See the [Open Source License] for more details.
#   */
#   /**
#   * Author: Zheng Wang
#   * Created: Jan. 4, 2023
#   * Supported by: National Key Research and Development Program of China
#   */


import time
import phot_engine as pe
import phot_engine.engine_shell.functional as F
from phot_engine import TaskPriority

"""
    无法执行,底层库已经更新!!!
"""
if __name__ == '__main__':
    """
        组件定义
            1. 定义参数
                1.1 列表式定义
                1.2 单独定义
            2. 定义组件
    """
    gen_bits_1_param_list = F.def_component_parameter(
        py_phot_name_list=["num_bits", ],
        data_type_list=["int", ],
        value_list=[262144, ],
        unit_list=["", ],
        phot_unit_list=["", ])

    gen_bits_1 = F.def_component(
        component_id="gen_bits_1",
        phot_class_name="gen_bits",
        phot_func_name="gen_bits",
        parameter_list=gen_bits_1_param_list,
        is_class=False,
        device="CPU",
        is_analyzer=False)

    qam_modulate_1_param_list = F.def_component_parameter(
        py_phot_name_list=["bits_per_symbol"],
        data_type_list=["int"],
        value_list=[6],
        unit_list=[""],
        phot_unit_list=[""])

    qam_modulate_1 = F.def_component(
        component_id="qam_modulate_1",
        phot_class_name="qam_modulate",
        phot_func_name="qam_modulate",
        parameter_list=qam_modulate_1_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    pulse_shaper_1_param_list = F.def_component_parameter(
        py_phot_name_list=["up_sampling_factor", "len_filter", "alpha", "ts", "fs"],
        data_type_list=["int", "int", "double", "double", "double"],
        value_list=[2, 256, 0.02, 0.00000000005, 40e9],
        unit_list=["", "", "", "", ""],
        phot_unit_list=["", "", "", "", ""])

    pulse_shaper_1 = F.def_component(
        component_id="PulseShaper_1",
        phot_class_name="PulseShaper",
        phot_func_name="tx_shape",
        parameter_list=pulse_shaper_1_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    dac_noise_1_param_list = F.def_component_parameter(
        py_phot_name_list=["sampling_rate_awg", "sampling_rate", "dac_resolution_bits"],
        data_type_list=["double", "double", "int"],
        value_list=[96e9, 40e9, 8],
        unit_list=["", "", ""],
        phot_unit_list=["", "", ""])

    dac_noise_1 = F.def_component(
        component_id="DacNoise_1",
        phot_class_name="dac_noise",
        phot_func_name="dac_noise",
        parameter_list=dac_noise_1_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    phase_noise_1_param_list = F.def_component_parameter(
        py_phot_name_list=["over_sampling_rate", "linewidth", "symbol_rate"],
        data_type_list=["double", "double", "double"],
        value_list=["2.0", 150e3, 20e9],
        unit_list=["", "", ""],
        phot_unit_list=["", "", ""])

    phase_noise_1 = F.def_component(
        component_id="phase_noise_1",
        phot_class_name="phase_noise",
        phot_func_name="phase_noise",
        parameter_list=phase_noise_1_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    gaussian_noise_1_param_list = F.def_component_parameter(
        py_phot_name_list=["osnr", "sampling_rate"],
        data_type_list=["double", "double"],
        value_list=["50", "40e9"],
        unit_list=["", ""],
        phot_unit_list=["", ""])

    gaussian_noise_1 = F.def_component(
        component_id="gaussian_noise_1",
        phot_class_name="gaussian_noise",
        phot_func_name="gaussian_noise",
        parameter_list=gaussian_noise_1_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    optical_fiber_channel_1_param_list = F.def_component_parameter(
        py_phot_name_list=["sampling_rate", "span", "num_steps", "beta2", "delta_z", "gamma", "alpha", "L"],
        data_type_list=["double", "int", "int", "double", "float", "float", "float", "int"],
        value_list=["40e9", "5", 75, "21.6676e-24", 1.0, 1.3, "0.2", 75],
        unit_list=["", "", "", "", "", "", "", ""],
        phot_unit_list=["", "", "", "", "", "", "", ""])

    optical_fiber_channel_1 = F.def_component(
        component_id="optical_fiber_channel_1",
        phot_class_name="optical_fiber_channel",
        phot_func_name="optical_fiber_channel",
        parameter_list=optical_fiber_channel_1_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False
    )

    phase_noise_2_param_list = F.def_component_parameter(
        py_phot_name_list=["over_sampling_rate", "linewidth", "symbol_rate"],
        data_type_list=["double", "float", "double"],
        value_list=["2.0", "150e3", "20e9"],
        unit_list=["", "", ""],
        phot_unit_list=["", "", ""]
    )

    phase_noise_2 = F.def_component(
        component_id="phase_noise_2",
        phot_class_name="phase_noise",
        phot_func_name="phase_noise",
        parameter_list=phase_noise_2_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    add_freq_offset_1_param_list = F.def_component_parameter(
        py_phot_name_list=["frequency_offset", "sampling_rate"],
        data_type_list=["double", "double"],
        value_list=["2e9", "40e9"],
        unit_list=["", ""],
        phot_unit_list=["", ""])

    add_freq_offset_1 = F.def_component(
        component_id="add_freq_offset_1",
        phot_class_name="add_freq_offset",
        phot_func_name="add_freq_offset",
        parameter_list=add_freq_offset_1_param_list,
        is_class=False,
        device="CPU",
        is_analyzer=False)

    add_iq_imbalance_1_param_list = F.def_component_parameter(
        py_phot_name_list=[],
        data_type_list=[],
        value_list=[],
        unit_list=[],
        phot_unit_list=[])

    add_iq_imbalance_1 = F.def_component(
        component_id="add_iq_imbalance_1",
        phot_class_name="add_iq_imbalance",
        phot_func_name="add_iq_imbalance",
        parameter_list=add_iq_imbalance_1_param_list,
        is_class=False,
        device="CPU",
        is_analyzer=False)

    adc_noise_1_param_list = F.def_component_parameter(
        py_phot_name_list=["sampling_rate", "adc_sample_rate", "adc_resolution_bits", ],
        data_type_list=["double", "double", "int", ],
        value_list=["40e9", "160e9", "8", ],
        unit_list=["", "", "", ],
        phot_unit_list=["", "", "", ])

    adc_noise_1 = F.def_component(
        component_id="adc_noise_1",
        phot_class_name="adc_noise",
        phot_func_name="adc_noise",
        parameter_list=adc_noise_1_param_list,
        is_class=False,
        device="CPU",
        is_analyzer=False)

    iq_compensation_1_param_list = F.def_component_parameter(
        py_phot_name_list=["sampling_rate", "beta2", "span", "L"],
        data_type_list=["double", "float", "int", "int"],
        value_list=["40e9", "21.6676e-24", 5, "75"],
        unit_list=["", "", "", "", ],
        phot_unit_list=["", "", "", "", ])

    iq_compensation_1 = F.def_component(
        component_id="iq_freq_offset_and_compensation_1",
        phot_class_name="iq_freq_offset_and_compensation",
        phot_func_name="iq_freq_offset_and_compensation",
        parameter_list=add_freq_offset_1_param_list,
        is_class=False,
        device="CPU",
        is_analyzer=False)

    freq_offset_compensation_1_param_list = F.def_component_parameter(
        py_phot_name_list=["sampling_rate", ],
        data_type_list=["double", ],
        value_list=["40e9", ],
        unit_list=["", ],
        phot_unit_list=["", ])

    freq_offset_compensation_1 = F.def_component(
        component_id="iq_freq_offset_and_compensation_1",
        phot_class_name="iq_freq_offset_and_compensation",
        phot_func_name="iq_freq_offset_and_compensation",
        parameter_list=freq_offset_compensation_1_param_list,
        is_class=False,
        device="CPU",
        is_analyzer=False)

    pulse_shaper_2_param_list = F.def_component_parameter(
        py_phot_name_list=["up_sampling_factor", "len_filter", "alpha", "ts", "fs"],
        data_type_list=["int", "int", "double", "double", "double"],
        value_list=[2, 256, 0.02, 0.00000000005, 40e9],
        unit_list=["", "", "", "", ""],
        phot_unit_list=["", "", "", "", ""])

    pulse_shaper_2 = F.def_component(
        component_id="PulseShaper_2",
        phot_class_name="PulseShaper",
        phot_func_name="rx_shape",
        parameter_list=pulse_shaper_2_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    sync_frame_1_param_list = F.def_component_parameter(
        py_phot_name_list=["up_sampling_factor"],
        data_type_list=["int"],
        value_list=["2"],
        unit_list=["", ],
        phot_unit_list=["", ])

    sync_frame_1 = F.def_component(
        component_id="sync_frame_1",
        phot_class_name="sync_frame",
        phot_func_name="sync_frame",
        parameter_list=sync_frame_1_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    adaptive_equalize_1_param_list = F.def_component_parameter(
        py_phot_name_list=["num_tap", "cma_convergence", "ref_power_cma", "step_size_cma", "step_size_rde",
                           "up_sampling_factor", "bits_per_symbol", "total_baud", ],
        data_type_list=["int", "int", "int", "float", "float", "int", "int", "float", ],
        value_list=["25", "30000", "2", "1e-9", "1e-9", "2", "6", "20e9", ],
        unit_list=["", "", "", "", "", "", "", "", ],
        phot_unit_list=["", "", "", "", "", "", "", "", ])

    adaptive_equalize_1 = F.def_component(
        component_id="adaptive_equalize_1",
        phot_class_name="adaptive_equalize",
        phot_func_name="adaptive_equalize",
        parameter_list=adaptive_equalize_1_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    bps_restore_1_param_list = F.def_component_parameter(
        py_phot_name_list=["num_test_angle", "block_size", "bits_per_symbol", ],
        data_type_list=["int", "int", "int", ],
        value_list=["64", "100", "6", ],
        unit_list=["", "", "", ],
        phot_unit_list=["", "", "", ])

    bps_restore_1 = F.def_component(
        component_id="bps_restore_1",
        phot_class_name="bps_restore",
        phot_func_name="bps_restore",
        parameter_list=bps_restore_1_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    bits_error_count_1_param_list = F.def_component_parameter(
        py_phot_name_list=["bits_per_symbol", ],
        data_type_list=["int", ],
        value_list=["6", ],
        unit_list=["", ],
        phot_unit_list=["", ])

    bits_error_count_1 = F.def_component(
        component_id="bits_error_count_1",
        phot_class_name="bits_error_count",
        phot_func_name="bits_error_count",
        parameter_list=bits_error_count_1_param_list,
        is_class=True,
        device="CPU",
        is_analyzer=False)

    # """
    #     系统构建
    #         1. 构建边
    # """
    edge_1 = F.def_edge(source_component=gen_bits_1, source_port=0, destination_component=qam_modulate_1,
                        destination_port=0)
    edge_2 = F.def_edge(source_component=qam_modulate_1, source_port=0, destination_component=pulse_shaper_1,
                        destination_port=0)
    edge_3 = F.def_edge(source_component=pulse_shaper_1, source_port=0, destination_component=dac_noise_1,
                        destination_port=0)
    edge_4 = F.def_edge(source_component=dac_noise_1, source_port=0, destination_component=phase_noise_1,
                        destination_port=0)
    edge_5 = F.def_edge(source_component=phase_noise_1, source_port=0, destination_component=gaussian_noise_1,
                        destination_port=0)
    edge_6 = F.def_edge(source_component=gaussian_noise_1, source_port=0, destination_component=optical_fiber_channel_1,
                        destination_port=0)
    edge_7 = F.def_edge(source_component=optical_fiber_channel_1, source_port=0, destination_component=phase_noise_2,
                        destination_port=0)
    edge_8 = F.def_edge(source_component=phase_noise_2, source_port=0, destination_component=add_freq_offset_1,
                        destination_port=0)
    edge_9 = F.def_edge(source_component=add_freq_offset_1, source_port=0, destination_component=add_iq_imbalance_1,
                        destination_port=0)
    edge_10 = F.def_edge(source_component=add_iq_imbalance_1, source_port=0, destination_component=adc_noise_1,
                         destination_port=0)
    edge_11 = F.def_edge(source_component=adc_noise_1, source_port=0,
                         destination_component=iq_compensation_1, destination_port=0)
    edge_12 = F.def_edge(source_component=optical_fiber_channel_1, source_port=1,
                         destination_component=iq_compensation_1, destination_port=1)
    edge_20 = F.def_edge(source_component=iq_compensation_1, source_port=1,
                         destination_component=freq_offset_compensation_1, destination_port=1)
    edge_13 = F.def_edge(source_component=freq_offset_compensation_1, source_port=0,
                         destination_component=pulse_shaper_2, destination_port=0)

    edge_14 = F.def_edge(source_component=pulse_shaper_2, source_port=0, destination_component=sync_frame_1,
                         destination_port=0)
    edge_15 = F.def_edge(source_component=qam_modulate_1, source_port=0, destination_component=sync_frame_1,
                         destination_port=1)
    edge_16 = F.def_edge(source_component=sync_frame_1, source_port=0, destination_component=adaptive_equalize_1,
                         destination_port=0)
    edge_17 = F.def_edge(source_component=adaptive_equalize_1, source_port=0, destination_component=bps_restore_1,
                         destination_port=0)
    edge_18 = F.def_edge(source_component=bps_restore_1, source_port=0, destination_component=bits_error_count_1,
                         destination_port=0)
    edge_19 = F.def_edge(source_component=sync_frame_1, source_port=1, destination_component=bits_error_count_1,
                         destination_port=1)

    #
    # """
    #     生成仿真任务
    # """
    simulation_task = F.generate_simulation_task(task_id="test_project", priority=TaskPriority.MIDDLE,
                                                 component_list=[gen_bits_1, qam_modulate_1,
                                                                 pulse_shaper_1, dac_noise_1,
                                                                 phase_noise_1, gaussian_noise_1,
                                                                 optical_fiber_channel_1,
                                                                 phase_noise_2, add_freq_offset_1,
                                                                 add_iq_imbalance_1, adc_noise_1,
                                                                 freq_offset_compensation_1,
                                                                 iq_compensation_1, pulse_shaper_2,
                                                                 sync_frame_1, adaptive_equalize_1,
                                                                 bps_restore_1, bits_error_count_1],
                                                 edge_list=[edge_1, edge_2, edge_3, edge_4, edge_5,
                                                            edge_6, edge_7, edge_8, edge_9, edge_10,
                                                            edge_11, edge_12, edge_13, edge_14, edge_15,
                                                            edge_16, edge_17, edge_18, edge_19,edge_20
                                                            ])

    print(simulation_task.show_task_info())

    engine = pe.PhotLabEngine()
    engine.add_task(simulation_task.get_task_id(), simulation_task)

    print("Simulation Task Status: ", engine.get_task_status("test_project"))
    print("\033[0;32; mEngine starts calculation!\033[0m")
    s_time = time.time()
    engine.calculate_task(simulation_task.get_task_id())
    e_time = time.time()
    print("\033[0;31; mEngine finished calculation!\033[0m")
    print("Simulation Task Status: {},time:{} s".format(engine.get_task_status("test_project"), str(e_time - s_time)))

    if engine.get_task_status("test_project") == pe.TaskStatus.TASK_DIED:
        error_queue = engine.get_task_exception_information("test_project")
        while not error_queue.empty():
            print("异常信息:", error_queue.get())
    else:
        result_edge_list = engine.get_task("test_project").get_edge_list()
        print("\033[0;32; m********** Engine got some interesting results **********\033[0m")
        print("result edge list id:{},length:{}".format(id(result_edge_list), len(result_edge_list)))
        cnt = 1
        for edge in result_edge_list:
            if edge.signal is not None:
                print("********************\n")
                print("Source port:{},Destination Port:{},signal:{}".format(edge.source_port,
                                                                            edge.destination_port,
                                                                            edge.signal))
                print("********************\n")
                cnt += 1
